#include "imageprocessor.h"
#include <math.h>
#include "string.h"
#define null 0
#define MATRIX(matrix,r,c,width) matrix[r*width+c]

#define PIXEL(p,x,y,perline,perpix) p[(int)(y)*perline+(int)(x)*perpix]


QImage OpenImage(QImage*m_raw_image,float*matrix,int matrix_width,int matrix_height,bool bin)
{
    DilationErosion DilationP(true,bin);
    DilationErosion ErosionP(false,bin);

    return ConvImage(
                &ConvImage(m_raw_image,matrix,matrix_width,matrix_height,&ErosionP)
                ,matrix,matrix_width,matrix_height,&DilationP);
}

QImage CloseImage(QImage*m_raw_image,float*matrix,int matrix_width,int matrix_height,bool bin)
{
    DilationErosion DilationP(true,bin);
    DilationErosion ErosionP(false,bin);
    return ConvImage(
                &ConvImage(m_raw_image,matrix,matrix_width,matrix_height,&DilationP)
                ,matrix,matrix_width,matrix_height,&ErosionP);
}
void AndOperation(uchar* dest,uchar*src1,uchar*src2,void* factor)
{
    if(*src1 > 0 && *src2>0)
        *dest = 255;
    else
        *dest = 0;
}

QImage MorReconstruction(QImage*m_raw_image,float*matrix,int matrix_width,int matrix_height)
{
    int arg = 1;
    DilationErosion DilationP(true);
    float ESE[9] = {1,1,1,
                    1,1,1,
                   1,1,1};
    QImage T;
    int i = 0;
    QImage M = OpenImage(m_raw_image,matrix,matrix_width,matrix_height);
    do{
        T = M;
        M = ConvImage(&M,ESE,3,3,&DilationP);
        M = BinaryImageOperation(m_raw_image,&M,MultiOperation,(void*)&arg);
        i++;
    }while(memcmp(M.bits(),T.bits(),M.byteCount())!=0 && i <10);
    return M;
}

void GetGrayHist(float* hist,QImage*m_raw_image)
{
    uchar *p = m_raw_image->bits();
    memset(hist,0,sizeof(float)*256);
    int total = m_raw_image->height()*m_raw_image->width();
    int total_pix = m_raw_image->height() * m_raw_image->bytesPerLine();
    for(int i = 0;i<total_pix;i+=3)
    {
        hist[(p[i]+p[i+1]+p[i+2])/3]++;
    }
    for(int i = 0;i<256;i++)
        hist[i] /= (float)total;

}

void Equalization(float*src_hist,float*dest_hist,float *map)
{
    float sum = 0;
    for (int i=0;i<256;i++)
    {
        sum += 255*src_hist[i];
        map[i] = sum;
        dest_hist[i] = 0;
    }
    for (int i=0;i<256;i++)
    {
        dest_hist[qFloor(map[i])] += src_hist[i];
    }
}

QImage ZoomImage(QImage*m_raw_image,int new_height,int new_width,short zoom_mode)
{
    QSize size = m_raw_image->size();
    QImage new_image(new_width,new_height,QImage::Format_RGB888);
    uchar* new_image_p = new_image.bits();
    uchar* raw_image_p = m_raw_image->bits();
    int raw_bytes_per_line = m_raw_image->bytesPerLine();
    int raw_bytes_per_pix = m_raw_image->bytesPerLine()/size.width();
    int new_bytes_per_line = new_image.bytesPerLine();
    int new_bytes_per_pix = new_bytes_per_line /new_width;

    float height_ratio = new_height / (float)size.height();
    float width_ratio = new_width /(float)size.width();

    uchar* dy_new_image_p;
    int Index1,Index2;

    float PosX,PosY;
    int NewX,NewY,PartX,PartY,InvX,InvY;
    for(int i = 0;i<new_height;i++)
    {
        PosY = i / height_ratio;
        for(int j = 0 ;j<new_width;j++)
        {
            PosX = j /width_ratio;
            if(PosY >= size.height()-1 || PosX>=size.width()-1)continue;
            dy_new_image_p = &PIXEL(new_image_p,j,i,new_bytes_per_line,new_bytes_per_pix);


            if(zoom_mode == 0)
            {
                NewX = int(PosX);
                NewY = int(PosY);
                PartX = (PosX - NewX) *2048;
                PartY = (PosY - NewY) *2048 ;
                InvX = 2048 - PartX ;
                InvY = 2048 - PartY ;

                Index1 = raw_bytes_per_line * NewY + NewX * raw_bytes_per_pix;
                Index2 = Index1 + raw_bytes_per_line;

                dy_new_image_p[0] =((raw_image_p[Index1] * InvX + raw_image_p[Index1 + raw_bytes_per_pix] * PartX) * InvY + (raw_image_p[Index2] * InvX +
                                          raw_image_p[Index2 + raw_bytes_per_pix] * PartX) * PartY)>>22;
                dy_new_image_p[1] = ((raw_image_p[Index1 + 1] * InvX + raw_image_p[Index1 + 1+raw_bytes_per_pix] * PartX) * InvY + (raw_image_p[Index2 + 1] * InvX +
                                          raw_image_p[Index2 + 1+raw_bytes_per_pix] * PartX) * PartY)>>22;
                dy_new_image_p[2] = ((raw_image_p[Index1 + 2] * InvX + raw_image_p[Index1 + 2+raw_bytes_per_pix] * PartX) * InvY + (raw_image_p[Index2 + 2] * InvX +
                                          raw_image_p[Index2 + 2+raw_bytes_per_pix] * PartX) * PartY) >>22;
            }

            else if(zoom_mode == 1)
            {
                NewX = (int)(PosX +0.5);
                NewY = (int)(PosY +0.5);
                dy_new_image_p[0] = raw_image_p[NewY * raw_bytes_per_line + raw_bytes_per_pix * NewX];
                dy_new_image_p[1] = raw_image_p[NewY * raw_bytes_per_line + raw_bytes_per_pix * NewX+1];
                dy_new_image_p[2] = raw_image_p[NewY * raw_bytes_per_line + raw_bytes_per_pix * NewX+2];

            }

            else if(zoom_mode == 2)
            {
            }
        }
    }
    return new_image;
}

inline int Med(int* array,int num)
{
    int temp[9];
    int t,min;
    for(int i = 0;i<9;temp[i]=i++);
    for(int i =0;i<num+1;i++)
    {
        min = array[temp[i]];
        t = i;
        for(int j=i;j<9;j++)
        {
            if(array[temp[j]] < min)
            {
                min = array[temp[j]];
                t = j;
            }
        }
        min = temp[i];
        temp[i] = temp[t];
        temp[t] = min;
    }
    return temp[num];
}

QImage MedianFilter(QImage* m_raw_image)
{

    QImage conv_image =QImage(m_raw_image->size(),QImage::Format_RGB888);
    QImage* m_conv_image = &conv_image;


    uchar* base_p = m_raw_image->bits();
    uchar* new_base_p = m_conv_image->bits();


    int height = m_raw_image->height();
    int width = m_raw_image->width();
    int stride = m_raw_image->bytesPerLine();


    int a[9];
    for(int y = 0;y<height;y++)                         //image pix y
    {
        int med_y = 4;
        if(y == 0 || y ==height-1)
            med_y = med_y >>1;
        for(int x = 0;x<width;x++)        //image pix byte x
        {
            int med_x = med_y;
            if( x== 0|| x ==width-1)
                med_x = med_x>>1;
            for(int i = -1;i<=1;i++)
                for(int j=-1;j<=1;j++)
                {
                    if(x+j >= stride || x+j < 0 ||
                       y+i >= height || y+i < 0)
                    {
                        a[(i+1)*3+j+1] = 300;
                        continue;
                    }
                    int gray = (base_p[(y+i)*stride+(x+j)*3] +
                                base_p[(y+i)*stride+(x+j)*3+1] +
                                base_p[(y+i)*stride+(x+j)*3+2])/3;
                    a[(i+1)*3 +j +1] = gray;
                }
            int re = Med(a,med_x) ;
            int tempy = re/3-1;
            int tempx = re%3-1;
            new_base_p[y*stride+x*3]=base_p[(y+tempy)*stride + (x+tempx)*3];
            new_base_p[y*stride+x*3+1]=base_p[(y+tempy)*stride + (x+tempx)*3+1];
            new_base_p[y*stride+x*3+2]=base_p[(y+tempy)*stride + (x+tempx)*3+2];
        }
    }
    return *m_conv_image;
}

void ConvMatrix(uchar*raw,int width,int height,float *matrix,int matrix_width, int matrix_height,ConvProcessor* processor,uchar* dest,int center_x,int center_y)
{
    if(center_x < 0)center_x = matrix_width >>1;
    if(center_y < 0)center_y = matrix_height >>1;
    for(int i = 0;i<height;i++)
    {
        for(int j = 0;j<width;j++)
        {
            processor->Begin(i,j,raw[i*width+j]);
            for(int m_i=0;m_i<matrix_height;m_i++)
            {
                for(int m_j = 0;m_j<matrix_width;m_j++)
                {
                    if((m_i+i-center_y) < 0 ||
                            (m_i+i-center_y)>=height)
                    {
                        processor->OutOfBoundary(m_i,m_j,MATRIX(matrix,m_j,m_i,matrix_width));
                        continue;
                    }
                    if((m_j+j-center_x) < 0 ||
                            (m_j+j-center_x)>=width)
                    {
                        processor->OutOfBoundary(m_i,m_j,MATRIX(matrix,m_j,m_i,matrix_width));
                        continue;
                    }
                    processor->Input(m_i,m_j,raw[(m_i+i-center_y)*width+m_j+j-center_x],MATRIX(matrix,m_i,m_j,matrix_width));
                }
            }
            int ret = processor->Finish();
            if(dest != 0)
                dest[i*width + j] = ret;
        }
    }
}



QImage ConvImage(QImage *m_raw_image, float *matrix, int matrix_width, int matrix_height,ConvProcessor *processor,
                 int matrix_center_x,int matrix_center_y)
{
    QSize size = m_raw_image->size();
    QImage conv_image =QImage(size,QImage::Format_RGB888);
    QImage* m_conv_image = &conv_image;
    int origin_x;

    if(matrix_center_x < 0) matrix_center_x = matrix_width >> 1;
    if(matrix_center_y < 0) matrix_center_y = matrix_height >> 1;
    int bytes_per_line = m_conv_image->bytesPerLine();
    int bytes_per_pix = bytes_per_line/size.width();

    uchar* base_p = m_raw_image->bits();
    uchar* new_base_p = m_conv_image->bits();
    uchar* upper_boundary = m_raw_image->bits() + bytes_per_line * size.height() -3;

    int height = size.height();
    int width = size.width();
    uchar* dy_p;
    uchar** Index = new uchar*[matrix_height];
    for(int i = 0;i<matrix_height;i++)
    {
        Index[i] = base_p + (i-matrix_center_y)*bytes_per_line;
    }

    for(int y = 0;y<height;y++)
        for(int x = 0;x<width;x++)
        {
            for(int r = 0; r<bytes_per_pix;r++)
            {
                processor->Begin(y,x);
                for(int matrix_y = 0;matrix_y<matrix_height;matrix_y++)
                {
                    uchar* p_line = base_p+(y+matrix_y-matrix_center_y)*bytes_per_line;
                    for(int matrix_x = 0;matrix_x<matrix_height;matrix_x++)
                    {
                        if(p_line>upper_boundary || p_line<base_p)
                        {
                            processor->OutOfBoundary(matrix_y,matrix_x,MATRIX(matrix,matrix_y,matrix_x,matrix_width));
                            continue;
                        }
                        dy_p = p_line + (x+matrix_x-matrix_center_x)*bytes_per_pix + r;
                        if(dy_p < p_line || dy_p >=p_line+bytes_per_line-3)
                        {
                            processor->OutOfBoundary(matrix_y,matrix_x,MATRIX(matrix,matrix_y,matrix_x,matrix_width));
                            continue;
                        }
                        processor->Input(matrix_y,matrix_x,*dy_p,MATRIX(matrix,matrix_y,matrix_x,matrix_width));
                    }
                }
                new_base_p[y*bytes_per_line + bytes_per_pix*x+r] = processor->Finish();

            }
        }
//    for(int y = 0;y<height;y++)                         //image pix y
//    {
//        for(int x = 0;x<bytes_per_line;x++)        //image pix byte x
//        {
//            origin_x = x-matrix_center_x*bytes_per_pix;             //pattern start x
//            processor->Begin();
//            for(int matrix_y = 0;matrix_y < matrix_height;matrix_y++)   //matrix start y
//            {

//                for(int matrix_x=0;matrix_x<matrix_width;matrix_x++)    //matrix start x
//                {
//                    if(Index[matrix_y]<base_p || Index[matrix_y] > upper_boundary)    //if line out of boundary fill 0
//                    {
//                        processor->OutOfBoundary(matrix_y,matrix_x,MATRIX(matrix,matrix_y,matrix_x,matrix_width));
//                        continue;
//                    }
//                    if(origin_x+matrix_x*bytes_per_pix < 0 ||
//                            origin_x+matrix_x*bytes_per_pix >= bytes_per_line)
//                    {
//                        processor->OutOfBoundary(matrix_y,matrix_x,MATRIX(matrix,matrix_y,matrix_x,matrix_width));
//                        continue;
//                    }
//                    dy_p = &Index[matrix_y][origin_x+matrix_x*bytes_per_pix];
//                    processor->Input(matrix_y,matrix_x,*dy_p ,MATRIX(matrix,matrix_y,matrix_x,matrix_width));
//                }
//            }
//            int new_c = processor->Finish();
//            new_base_p[y*bytes_per_line + x] = new_c;

//        }
//        for(int i = 0;i<matrix_height;i++)
//            Index[i] += bytes_per_line;
//    }
    return *m_conv_image;
}

QImage ConvImage(QImage* m_raw_image,float *matrix, int matrix_width,int matrix_height,float division)
{

    QSize size = m_raw_image->size();
    QImage conv_image =QImage(size,QImage::Format_RGB888);
    QImage* m_conv_image = &conv_image;
    int origin_x;

    int matrix_half_width = matrix_width>>1;
    int matrix_half_height = matrix_height>>1;

    int bytes_per_line = m_conv_image->bytesPerLine();
    int bytes_per_pix = bytes_per_line/size.width();

    uchar* base_p = m_raw_image->bits();
    uchar* new_base_p = m_conv_image->bits();
    uchar* upper_boundary = m_raw_image->bits() + bytes_per_line * size.height() -3;

    int height = size.height();

    uchar* dy_p;
    uchar** Index = new uchar*[matrix_height];
    for(int i = 0;i<matrix_height;i++)
    {
        Index[i] = base_p + (i-matrix_half_height)*bytes_per_line;
    }

    int sum;
    for(int y = 0;y<height;y++)                         //image pix y
    {
        //origin_y = y-matrix_half_height;
        for(int x = 0;x<bytes_per_line;x++)        //image pix byte x
        {
            origin_x = x-matrix_half_width*bytes_per_pix;             //pattern start x
            sum = 0;
            for(int matrix_y = 0;matrix_y < matrix_height;matrix_y++)   //matrix start y
            {
                if(Index[matrix_y]<base_p || Index[matrix_y] > upper_boundary)    //if line out of boundary fill 0
                    continue;
                for(int matrix_x=0;matrix_x<matrix_width;matrix_x++)    //matrix start x
                {
                    if(origin_x+matrix_x*bytes_per_pix < 0 ||
                            origin_x+matrix_x*bytes_per_pix >= bytes_per_line)
                        continue;
                    dy_p = &Index[matrix_y][origin_x+matrix_x*bytes_per_pix];
                    sum += *dy_p*MATRIX(matrix,matrix_y,matrix_x,matrix_width);

                }
            }
            sum /= division;
            if(sum >255)
                new_base_p[y * bytes_per_line + x] =255;
            else if(sum <0)
                new_base_p[y * bytes_per_line + x] = 0;
            else
                new_base_p[y * bytes_per_line + x] = sum;

        }
        for(int i = 0;i<matrix_height;i++)
            Index[i] += bytes_per_line;
    }
    return *m_conv_image;
}

QImage PointImageOperation(QImage*image,PointOperation operation,void* args)
{
    QImage new_image(image->size(),QImage::Format_RGB888);
    int total = image->width() * image->height();
    int per_pix = image->bytesPerLine()/image->width();
    uchar* p_raw = image->bits();
    uchar* p_new = new_image.bits();
    for(int i = 0;i<total;i++)
    {
        operation(&p_new[i*3],&p_raw[i*per_pix],args);
    }
    return new_image;
}

void GrayOperation(uchar* dest,uchar* src,void* args)
{
   dest[0] = dest[1]=dest[2]  = (src[0] + src[1] + src[2])/3;
}

void BinOperation(uchar* dest,uchar*src,void* args)
{
    int threshold = *(int *)args;
    dest[0] = dest[1] = dest[2] = ((src[0]+src[1]+src[2])/3)>threshold?255:0;
}

void RemapOperation(uchar* dest,uchar*src,void*args)
{
    float *temp = (float*)args;
    int gray = (src[0]+src[1]+src[2])/3;
    dest[0] = dest[1] = dest[2] = temp[gray];
}

void LightOperation(uchar* dest,uchar*src,void*args)
{
    int p = *(int*)args;
    int temp = src[0]+p;
    dest[0] = temp >255?255:temp<0?0:temp;
    temp = src[1]+p;
    dest[1] = temp >255?255:temp<0?0:temp;
    temp = src[2]+p;
    dest[2] = temp >255?255:temp<0?0:temp;
}

void ContrastOperation(uchar* dest,uchar* src,void* args)
{
    int p = *(int*)args +100;
    int temp = 127 + (src[0] - 127)* p /100;;
    dest[0] = temp >255?255:temp;
    temp = 127 + (src[1] - 127)* p /100;;
    dest[1] = temp >255?255:temp;
    temp = 127 + (src[2] - 127)* p /100;;
    dest[2] = temp >255?255:temp;
}

QImage BinaryImageOperation(QImage*image1,QImage*image_2,BinaryOperation operation,void* arg)
{
    int width1 = image1->size().width();
    int height1 = image1->size().height();



    int stride1 = image1->bytesPerLine();

    QImage image2a=image_2->scaled(image1->size());
    QImage *image2 = &image2a;
    QImage new_image = QImage(width1,height1,QImage::Format_RGB888);
    uchar* p1 = image1->bits();
    uchar* p2 = image2->bits();
    uchar* p_new = new_image.bits();


    for(int y = 0;y<height1;y++)
    {
        for(int x = 0;x<width1;x++)
        {
            operation(&p_new[y*stride1+x*3],
                      &p1[y*stride1 + x*3],
                      &p2[y*stride1 + x*3]
                      ,arg );
        }
    }

    return new_image;
}



void AddOperation(uchar* dest,uchar*src1,uchar*src2,void* factor)
{
    uint temp;
    temp = (src1[0]+src2[0]**(int*)factor);
    dest[0] = temp > 255?255:temp;
    temp = (src1[1]+src2[1]**(int*)factor);
    dest[1] = temp > 255?255:temp;
    temp = (src1[2]+src2[2]**(int*)factor);
    dest[2] = temp > 255?255:temp;
}

void SubOperation(uchar* dest,uchar*src1,uchar*src2,void* factor)
{
    uint temp;
    temp = (src1[0]-src2[0]**(int*)factor);
    dest[0] = temp < 0?0:temp;
    temp = (src1[1]-src2[1]**(int*)factor);
    dest[1] = temp < 0?0:temp;
    temp = (src1[2]-src2[2]**(int*)factor);
    dest[2] = temp < 0?0:temp;
}

void MultiOperation(uchar* dest,uchar*src1,uchar*src2,void* factor)
{
    uint temp;
    temp = sqrt((float)(src1[0] * src2[0]**(int*)factor));
    dest[0] = temp > 255?255:temp;

    temp = sqrt((float)(src1[1] * src2[1]**(int*)factor));
    dest[1] = temp > 255?255:temp;

    temp = sqrt((float)(src1[2] * src2[2]**(int*)factor));
    dest[2] = temp > 255?255:temp;
}

void DivideOperation(uchar* dest,uchar*src1,uchar*src2,void* factor)
{
    uint temp;
    temp = sqrt((float)(src1[0] / (src2[0]**(int*)factor)));
    dest[0] = temp > 255?255:temp;

    temp = sqrt((float)(src1[1] / (src2[1]**(int*)factor)));
    dest[1] = temp > 255?255:temp;

    temp = sqrt((float)(src1[2] / (src2[2]**(int*)factor)));
    dest[2] = temp > 255?255:temp;
}

int GetBaseThreshold(float* gray,int delta)
{
        int preT,T;
        float m1,m2;
        int i;
        float total;
        T = 127;
        preT = 0;
        while(abs(preT-T)>=delta)
        {
            m1=0;
            m2=0;
            total = 0;
            for(i = 0;i<T;i++)
            {
                total+=gray[i];
                m1 += i*gray[i];
            }
            m1 /= total;
            total = 0;
            for(i = T;i<256;i++)
            {
                total+=gray[i];
                m2 += i*gray[i];
            }
            m2 /= total;
            preT = T;
            T = (m1+m2)/2;
        }
        return T;
}

int GetOstuThreshold(float* gray)
{
    float Pk[256];
        float mk[256];
        float mg,division,max_division;
        int i;
        float sum_k;
        int cnt_k;

        max_division = 0;
        memset(Pk,0,sizeof(float)*256);
        memset(mk,0,sizeof(float)*256);
        mg = 0;

        Pk[0] = gray[0];
        mk[0] = 0;
        float test = gray[0];
        for(i = 1;i<256;i++)
        {
            Pk[i] = Pk[i-1]+gray[i];
            mg += i*gray[i];
            mk[i] = mg;
        }

        for( i = 0;i<256;i++)
        {
            division = ((mg*Pk[i] - mk[i])*(mg*Pk[i] - mk[i]))/
                    (Pk[i]*(1-Pk[i]));
            if(division > max_division)
            {
                sum_k = i;
                cnt_k = 1;
                max_division = division;
            }
            else if(division == max_division)
            {
                sum_k += i;
                cnt_k ++;
            }
        }
        return sum_k/(float)cnt_k;
}

int GetThresholdEntropy(float* gray)
{
    float p[256];
    float P[256];
    float sum = 0, max = -1;
    int k = -1;
    for (int i = 0; i < 256; i++)
    {
        p[i] = gray[i];
        sum += p[i];
        P[i] = sum;
    }
    for (int t = 0; t < 256; t++)
    {
        float hb = 0, hw = 0;
        for (int i = 0; i < 256; i++)
        {
            float temp;
            if (i <= t)
            {
                temp = p[i] / P[t];
                hb += temp * qExp(1 - temp);
            }
            else
            {
                temp = p[i] / (1 - P[t]);
                hw += temp * qExp(1 - temp);
            }
        }
        float now = hb + hw;
        if (now > max)
        {
            max = now;
            k = t;
        }
    }
    return k;
}
QImage ToImage(uchar*src,int w,int h,bool one=false)
{
    int value;
    QImage image(w,h,QImage::Format_RGB888);
    int stride = image.bytesPerLine();
    uchar*p=image.bits();
    for(int i = 0;i<h;i++)
    {
        for (int j = 0;j<w;j++)
        {
            if(one)
                value = src[i*w+j]>0?255:0;
            else
                value = src[i*w+j];
            p[i*stride+3*j]=p[i*stride+3*j+1]=p[i*stride+3*j+2] = value;
        }
    }
    return image;
}

void ToMatrix(QImage *raw,uchar* dest,bool one = false)
{
    int w = raw->width();
    int h = raw->height();
    uchar*p=raw->bits();
    uchar*dy;
    int stride = raw->bytesPerLine();
    int bc = raw->bytesPerLine()/w;
    int sum;
    for(int i = 0;i<h;i++)
        for(int j = 0;j<w;j++)
        {
            sum = 0;
            dy = p+i*stride+j*bc;
            for(int c=0;c<bc;c++)
                sum+=dy[c];
            sum/=bc;
            if(one)
            {
                dest[i*w+j] = (sum>0)?1:0;
            }
            else
            {
                if(sum > 127)
                    dest[i*w+j] = 255;
                else
                    dest[i*w+j] = 0;
            }
        }
}

QImage DistanceTrans(QImage* m_raw_image)
{
    uchar *front_buff,*back_buff;
    front_buff = new uchar[m_raw_image->width()*m_raw_image->height()];
    back_buff = new uchar[m_raw_image->width()*m_raw_image->height()];
    ToMatrix(m_raw_image,front_buff);
    memcpy(back_buff,front_buff,sizeof(uchar)*m_raw_image->width()*m_raw_image->height());
    //return ToImage(front_buff,m_raw_image->width(),m_raw_image->height());
    float matrix[9] = {1,1,1,
                      1,1,1,
                      1,1,1,};
    int matrix_height = 3;
    int matrix_width = 3;

    DistanceProcessor dis(m_raw_image->width(),m_raw_image->height());
    do
    {
        dis.IterationBegin();
        ConvMatrix(front_buff,m_raw_image->width(),m_raw_image->height(),matrix,matrix_width,matrix_height,&dis,back_buff);
        uchar*temp = back_buff;
        back_buff = front_buff;
        front_buff = temp;

    }while(!dis.IterationEnd());
    float scale = 255.0/static_cast<float>(dis.max);
    for(int i = 0;i<m_raw_image->width()*m_raw_image->height();i++)
    {
        dis.Bitmap[i] *= scale;
    }
    QImage ret = ToImage(dis.Bitmap,m_raw_image->width(),m_raw_image->height());
    delete front_buff;
    delete back_buff;
    return ret;
}



class BinEroDiaProcessor:public ConvProcessor
{
public:

    BinEroDiaProcessor(bool Dilation){dialation = Dilation;count = 0;}

    void IterationBegin(){count = 0;}

    int IterationEnd(){return count;}

    virtual void Begin(int x,int y,int value){v=dialation?0:1;preV=value;}

    virtual void Input(int i ,int j,int value,int kernel)
    {
        v = dialation?((value&&kernel)?1:v):(!value && kernel?0:v);

    }

    virtual void OutOfBoundary(int i ,int j ,int kernel){}
    virtual int Finish()
    {
        if(preV!=v)
            count++;
        return ConvProcessor::Finish();
    }

    int count;
private:
    int preV;
    bool dialation;
};


QImage SkeletonRestruction(QImage* m_raw_image,int K,float*matrix,int m_w,int m_h)
{
//    float matrix[9] = {0,1,0,
//                       1,1,1,
//                       0,1,0};

    int width = m_raw_image->width();
    int height = m_raw_image->height();

    uchar *SkA_front = new uchar[width*height];
    uchar* SkA_back = new uchar[width*height];
    uchar *result = new uchar[width*height];
    memset(result,0,sizeof(uchar)*width*height);;
    ToMatrix(m_raw_image,SkA_back);

    BinEroDiaProcessor processor(true);

    int i = 0;
    do
    {
        uchar *temp = SkA_back;
        SkA_back = SkA_front;
        SkA_front = temp;


        BinMatrix(result,SkA_front,result,width*height,BinAddOperation);

        ConvMatrix(SkA_front,width,height,matrix,m_w, m_h,&processor,SkA_back);

    }while(i++<K);


    QImage ret = ToImage(result,width,height,true);
    delete SkA_front;
    delete SkA_back;
    delete result;
    return ret;
}

QImage Skeleton(QImage* m_raw_image,int*k,float*matrix,int m_w,int m_h)
{
//    float matrix[9] = {0,1,0,
//                       1,1,1,
//                       0,1,0};

    int width = m_raw_image->width();
    int height = m_raw_image->height();

    uchar *SkA = new uchar[width*height];
    uchar *result = new uchar[width*height];
    memset(result,0,sizeof(uchar)*width*height);
    uchar *buffer = new uchar[width*height];
    uchar *buffer_2 = new uchar[width*height];
    uchar *AkB_front = new uchar[width*height];
    uchar *AkB_back = new uchar[width*height];
    ToMatrix(m_raw_image,AkB_back);

    BinEroDiaProcessor processor(false);

    BinEroDiaProcessor DiaP(true);
    BinEroDiaProcessor DiaE(false);
    *k = -1;
    do
    {
        uchar *temp = AkB_back;
        AkB_back = AkB_front;
        AkB_front = temp;

        ConvMatrix(AkB_front,width,height,matrix,m_w,m_h,&DiaE,buffer);

        ConvMatrix(buffer,width,height,matrix,m_w,m_h,&DiaP,buffer_2);


        BinMatrix(AkB_front,buffer_2,SkA,width*height,BinMinusOperation);

        BinMatrix(result,SkA,result,width*height,BinAddOperation);
        processor.IterationBegin();
        ConvMatrix(AkB_front,width,height,matrix,m_w,m_h,&processor,AkB_back);
        (*k)++;

    }while(processor.IterationEnd());


    QImage ret = ToImage(result,width,height,true);
    delete SkA;
    delete result;
    delete buffer;
    delete buffer_2;
    delete AkB_front;
    delete AkB_back;
    return ret;

}
